import  jwt
from fastapi import Depends, HTTPException, status, APIRouter, Cookie, Body
from fastapi import Response
from datetime import datetime, timedelta, timezone
from sqlalchemy.orm import Session
from config.app_static_ import *
from Model.user.User import *
from Model.default import  get_db
from passlib.context import CryptContext
from Model.user.response.main import Token, check_token_response, reset_user_info, user_info_public
from  celery.result import AsyncResult
from  celerywork.mycelery import celery_app
from func.judge.VerificationCode import get_email, Mail

# 哈希函数
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# 这是个哈希加密
user_info=APIRouter(prefix="/user",tags=["user"])
# oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/index/token")
# =======================================user-account==========================================


# 用户数据模型
def init_adminuser():
    try:
        session=get_db()

        if not session.query(user).filter_by(account='88888888',id=88888888).first():
            hash_ps=pwd_context.hash('LYS!88888888')
            admin=user(id=88888888,account='88888888',hash_ps=hash_ps,password="LYS_88888888",admin="valid")
            userexpand = user_expand(id=88888888, user_id=88888888)
            timeactivespan = time_active_span(user_id=88888888)
            usertimebehavior = user_time_behavior(user_id=88888888)

            session.add(admin)
            session.add(userexpand)
            session.add(timeactivespan)
            session.add(usertimebehavior)
            session.commit()
        else:
            pass
    except Exception as e:
        session.rollback()
        session.close()



# 生成 JWT Token 模板的函数
def create_access_token(data: dict, expires_delta: timedelta | None = None):
    to_encode = data.copy()
    expire = int((datetime.now(timezone.utc) + expires_delta).timestamp())
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# 验证用户密码
def verify_password(form_password: str, db_hashed_password: str):
    return pwd_context.verify(form_password, db_hashed_password)

# 获取数据库会话


# 用户注册
@user_info.post("/blog/create_ac")
def create_ac_ps(ac: str, ps: str, db: Session = Depends(get_db)):
    """
    只做普通用户的注册功能。
    :param ac:
    :param ps:
    :param db:
    :return:
    """

    try:
        judge=db.query(user).filter_by(account=ac).first()
        if judge is None:
            id_data = db.query(static_data).filter_by(id=1).first()
            if not id_data:
                raise HTTPException(status_code=500, detail="Static data not found")
            if id_data.user_id==88888888:
                id_data.user_id+=1
            User= user(id=id_data.user_id, account=ac, password=ps, hash_ps=pwd_context.hash(ps))
            #跟账户有关的直接信息静态单次,直接进行创建,不在处理时多次判断处理,减轻db操作压力
            userexpand=user_expand(id=id_data.user_id,user_id=id_data.user_id)
            timeactivespan=time_active_span(user_id=id_data.user_id)
            usertimebehavior=user_time_behavior(user_id=id_data.user_id)


            id_data.user_id += 1
            db.add(userexpand)
            db.add(usertimebehavior)
            db.add(timeactivespan)
            db.add(User)
            db.commit()
            return 1
        else:
            return status.HTTP_400_BAD_REQUEST
    except Exception as e:
        print(e)
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

# 账户信息设置
# 获取验证码采用在服务器进行比对
@user_info.get("/blog/VerificationCode/get")
def get_emailcode(sender:str,account:str,db:Session=Depends(get_db),email:Mail=Depends(get_email)):
    try:
        if db.query(user).filter_by(account=account,email=sender).first():
            result=celery_app.send_task("emailcode",args=(),expires=60*5,time_limit=60*0.5)
            email.send(f"这是你的验证码:{result.get()}",sender)
            return {"id":result.id}
        else:
            return status.HTTP_404_NOT_FOUND
    except Exception as e:
        print(e)
        return  status.HTTP_500_INTERNAL_SERVER_ERROR
@user_info.post("/blog/VerificationCode/judge")
def judge_emalicode(id:str,code:str):
    result=AsyncResult(id,app=celery_app)
    if result.get()==code:
        return 1
    else:
        return status.HTTP_404_NOT_FOUND

@user_info.post("/blog/reset_ac")
async  def reset_ac_ps(response:Response,reset_list:reset_user_info=Body(),db: Session = Depends(get_db)):
    """
    只做普通用户修改信息
    :param response:
    :param reset_list:
    :param db:
    :return:
    """
    # 这里将头像用base64直接存储
    id=reset_list.id
    ps=reset_list.password

    try:
        if id:
          user_data=db.query(user).filter_by(id=id).first()
        else:
            account=reset_list.account
            user_data=db.query(user).filter_by(account=account).first()

        if user_data:
            for row,clown in reset_list:
                if clown:
                    setattr(user_data, row, clown)
            if ps:
                user_data.hash_ps=pwd_context.hash(ps)
            db.commit()
            db.refresh(user_data)
            response.delete_cookie("access_token")
            access_token = create_access_token(
                    data={"sub": user_data.account}, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
            )
            response.set_cookie(
                key="access_token",  # Cookie 的名称
                value=f"Bearer {access_token}",  # Token 值，格式为 "Bearer <token>"
                max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60,  # Cookie 的过期时间（秒）
                httponly=True,  # 防止 JavaScript 访问
                secure=False,  # 仅通过 HTTPS 传输
                samesite='lax',  # 防止 CSRF 攻击
            )
            return 1
        else:
            return status.HTTP_401_UNAUTHORIZED
    except Exception as e:
        print(e)
        db.rollback()
        return status.HTTP_404_NOT_FOUND





# 用户登录获取 Token，并将 Token 存储在 Cookie 中
@user_info.post("/blog/token", response_model=Token)
async def login_for_access_token(response: Response, ac: str, ps: str,db: Session = Depends(get_db)):
    """
    获取cookie包裹的权证认为type=1认为是普通用户。0是管理用户
    :param response:
    :param ac:
    :param ps:
    :param type: 请求类型
    :param db:
    :return:
    """
    access_token = None
    try:
        user_data = db.query(user).filter_by(account=ac).first()
        if not user_data:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="账户不存在或未注册!"
            )
        if not verify_password(ps, user_data.hash_ps):
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="账户不存在或未注册!"
            )
        access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token(
            data={"sub": user_data.account}, expires_delta=access_token_expires
        )
        # 将 Token 存储在 Cookie 中
        response.set_cookie(
            key="access_token",  # Cookie 的名称
            value=f"Bearer {access_token}",  # Token 值，格式为 "Bearer <token>"
            max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60,  # Cookie 的过期时间（秒）
            httponly=False,  # 防止 JavaScript 访问
            secure=False,  # 仅通过 HTTPS 传输
            samesite='lax',  # 防止 CSRF 攻击
        )
        response.headers['Access-Control-Allow-Credentials']='true'
    except Exception as e:
           raise  HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="响应错误!"
            )


    return Token(**{"access_token": access_token, "token_type": "bearer",
                "user":user_data
                })


# 从 Cookie 中获取 Token
async def get_token_from_cookie(access_token: str = Cookie(None)):
    if not access_token:
        raise HTTPException(
             status_code=status.HTTP_401_UNAUTHORIZED,
             detail="Not authenticated",
             headers={"WWW-Authenticate": "Bearer"},
         )
    return access_token

# 验证 Token 并解析获取当前用户
async def get_current_user(token: str = Depends(get_token_from_cookie)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        # 去掉 "Bearer " 前缀
        if token.startswith("Bearer "):
            token = token[7:]
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        account: str = payload.get("sub")
        if account is None:
            raise credentials_exception
    except jwt.PyJWTError :
        raise credentials_exception
    return account

@user_info.get("/blog/judge/access_token",response_model=check_token_response)
async def check_token(token: str = Depends(get_token_from_cookie),db: Session = Depends(get_db)):
    """
    用来判断是否有token
    :param token:
    :return:
    """
    try:
        # 去掉 "Bearer " 前缀
        if token.startswith("Bearer "):
            token = token[7:]

        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        account=payload.get('sub')
        user_data=db.query(user).filter_by(account=account).first()
        if not user_data:
            raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            )

    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
        )
    return {
            'status': 'valid',
            'user': user_data,
    }
@user_info.post("/blog/status/change")
async def change_user_status(status: str, userid:int,db: Session = Depends(get_db),current_user: str = Depends(get_current_user)):
        try:
            db.query(user).filter_by(id=userid).update({"status": status})
            db.commit()
        except Exception as e:
            # 不做过多处理
            print(e)
            pass
        finally:
            db.close()



# 受保护的路由
@user_info.get("/protected")
async def protected_route(current_user: str = Depends(get_current_user)):
    return {"message": f"Hello, {current_user}"}

# 用户注销
@user_info.post("/logout")
async def logout(response: Response):
    response.delete_cookie("access_token")
    return {"message": "Logged out successfully"}

# 用于获取用户的公开类型的信息
@user_info.get("/blog/user_info_public")
async def deal_user_info_public(id:int,db:Session = Depends(get_db)):
    try:
         User = db.query(user).filter_by(id=id).first()
         middleuser=user.__dict__.copy()
         if User:
             return  user_info_public.from_orm(User)
         else:
             raise status.HTTP_404_NOT_FOUND
    except Exception as e:
        return  status.HTTP_500_INTERNAL_SERVER_ERROR
